﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;

namespace Firefly.Framework.Input
{
    public class MouseButtonMap : InputMap, IButtonMapEx<MouseButton, MouseManager, MouseButtonMapEventArgs>
    {
        public event EventHandler<MouseButtonMapEventArgs> MapDoubleClicked;

        private int _doubleClickMilliseconds;
        private bool _doubleClickCheck;

        public int DoubleClickThreshold { get; set; }

        public MouseButtonMap(MouseButton[] mappedButtons)
            : this(mappedButtons, string.Empty, 0, 200)
        {
        }

        public MouseButtonMap(MouseButton[] mappedButtons, string action)
            : this(mappedButtons, action, 0, 200)
        {
        }

        public MouseButtonMap(MouseButton[] mappedButtons, string action, int holdThreshold)
            : this(mappedButtons, action, holdThreshold, 200)
        {
        }

        public MouseButtonMap(MouseButton[] mappedButtons, string action, int holdThreshold, int doubleClickThreshold)
            : base()
        {
            InputMapType = InputMapType.MouseButtonMap;
            Action = action;
            HoldThreshold = holdThreshold;
            MappedButtons = new List<MouseButton>();
            DoubleClickThreshold = doubleClickThreshold;

            for (int i = 0; i < mappedButtons.Length; i++)
            {
                MappedButtons.Add(mappedButtons[i]);
            }

            InputService.Instance.RegisterInputMap(this);
        }

        private void NotifyDoubleClicked()
        {
            EventHandler<MouseButtonMapEventArgs> handler = MapDoubleClicked;

            if (handler != null)
            {
                handler(this, new MouseButtonMapEventArgs(this));
            }
        }

        #region IButtonMap Members

        public bool IsMapUp
        {
            get
            {
                bool status = false;

                foreach (MouseButton button in MappedButtons)
                {
                    if (Manager.IsButtonUp(button))
                    {
                        status = true;
                    }
                }

                return status;
            }
        }
        public bool IsMapDown
        {
            get
            {
                bool status = true;

                foreach (MouseButton button in MappedButtons)
                {
                    if (Manager.IsButtonUp(button))
                    {
                        status = false;
                    }
                }

                return status;
            }
        }
        public bool WasMapPressed
        {
            get
            {
                bool status = false;

                foreach (MouseButton button in MappedButtons)
                {
                    if (Manager.WasButtonUp(button))
                    {
                        status = true;
                    }
                }

                return (status && IsMapDown) ? true : false;
            }
        }
        public bool WasMapReleased
        {
            get
            {
                bool status = true;

                foreach (MouseButton button in MappedButtons)
                {
                    if (Manager.WasButtonUp(button))
                    {
                        status = false;
                    }
                }

                return (status && IsMapUp) ? true : false;
            }
        }
        public bool WasMapHeld
        {
            get
            {
                bool status = true;

                foreach (MouseButton button in MappedButtons)
                {
                    if (Manager.WasButtonUp(button))
                    {
                        status = false;
                    }
                }

                return (status && IsMapDown) ? true : false;
            }
        }

        #endregion

        #region IButtonMapEx Members

        public event EventHandler<MouseButtonMapEventArgs> MapHeld;
        public event EventHandler<MouseButtonMapEventArgs> MapPressed;
        public event EventHandler<MouseButtonMapEventArgs> MapReleased;

        private int _millisecondsHeld;

        public List<MouseButton> MappedButtons { get; private set; }
        public int HoldThreshold { get; set; }

        private void NotifyMapHeld()
        {
            EventHandler<MouseButtonMapEventArgs> handler = MapHeld;

            if (handler != null)
            {
                handler(this, new MouseButtonMapEventArgs(this));
            }
        }

        private void NotifyMapPressed()
        {
            EventHandler<MouseButtonMapEventArgs> handler = MapPressed;

            if (handler != null)
            {
                handler(this, new MouseButtonMapEventArgs(this));
            }
        }

        private void NotifyMapReleased()
        {
            EventHandler<MouseButtonMapEventArgs> handler = MapReleased;

            if (handler != null)
            {
                handler(this, new MouseButtonMapEventArgs(this));
            }
        }

        #endregion

        #region IHasInputManager Members

        public MouseManager Manager { get; set; }

        #endregion

        #region IUpdateable Members

        public override void Update(GameTime gameTime)
        {
            if (Enabled)
            {
                if (_doubleClickCheck)
                {
                    _doubleClickMilliseconds += gameTime.ElapsedRealTime.Milliseconds;
                }
                else
                {
                    _doubleClickMilliseconds = 0;
                }

                if (WasMapPressed)
                {
                    _millisecondsHeld = 0;
                    NotifyMapPressed();
                }
                else if (WasMapReleased)
                {
                    if (!_doubleClickCheck)
                    {
                        _doubleClickCheck = true;
                    }
                    else
                    {
                        _doubleClickCheck = false;

                        if (_doubleClickMilliseconds <= DoubleClickThreshold)
                        {
                            NotifyDoubleClicked();
                        }
                    }

                    NotifyMapReleased();
                }
                else if (WasMapHeld)
                {
                    _millisecondsHeld += gameTime.ElapsedRealTime.Milliseconds;

                    if (HoldThreshold > 0 && _millisecondsHeld >= HoldThreshold)
                    {
                        NotifyMapHeld();
                    }
                }
            }
        }

        #endregion
    }
}
